package entity.characters;

import static org.lwjgl.input.Keyboard.*;
import static org.lwjgl.input.Mouse.*;
import model.Model;

import org.lwjgl.util.vector.Vector3f;

import entity.Camera;
import entity.item.Item;

/**
 * 
 * @author Jevgeni Krutov
 *
 */
public final class Player extends Character {
	public final static int DEF_MAX_HEALTH = 200;
	private final static float DEF_MOVING_SPEED = 120f;
	
	private long timeToWaitBeforeNextAttack = 0;
	
	private Camera camera;
	
	private boolean isWon = false;

	public Player(Vector3f position, Vector3f rotation, Model model) {
		super(position, rotation, model, DEF_MAX_HEALTH);
	}

	@Override
	public void listenToActionAndMove(long elapsedTime) {
		if(camera.isFreeFloatingMode()) {
			return;
		}
		
		if (isButtonDown(0)) {
			if(timeToWaitBeforeNextAttack == 0) {
				isShooting = true;
				timeToWaitBeforeNextAttack = weapon.getWaitInterval();
			}
		}
		
        // Look up/down
        addRotation(getDY() * 0.5f, 0, 0);
        // Turn left/right
        addRotation(0, -getDX() * 0.5f, 0);
        
        
    	handleMovement(elapsedTime);
        
        // Jump
        if (isKeyDown(KEY_SPACE))
        	if(isGrounded())
        		jump();
	}
	
	private void handleMovement(long elapsedTime) {	
		Vector3f sum = new Vector3f(0, 0, 0);
    	
        // front
        if (isKeyDown(KEY_W))
        	applyMovementComponent(-1, 0, elapsedTime, sum);

        // back
        if (isKeyDown(KEY_S))
        	applyMovementComponent(1, 0, elapsedTime, sum);

        // left
        if (isKeyDown(KEY_A))
        	applyMovementComponent(1, -1, elapsedTime, sum);

        // right
        if (isKeyDown(KEY_D))
        	applyMovementComponent(-1, -1, elapsedTime, sum);
        
        if(sum.length() > 0f) {
        	sum.normalise();
        	float movingFactor = isGrounded() ? DEF_MOVING_SPEED : DEF_MOVING_SPEED / 7f;
        	sum.scale(movingFactor);
        	this.applyForce(sum);
        }
	}

	private void applyMovementComponent(float amount, float direction, long elapsedTime, Vector3f sum) {
		float xMoveFactor = (float) (elapsedTime * amount * Math.sin(Math.toRadians(rotation.y + 90 * direction)));
		float zMoveFactor = (float) (elapsedTime * amount * Math.cos(Math.toRadians(rotation.y + 90 * direction)));	
		
		Vector3f xMoveComponent = (Vector3f) new Vector3f(1,0,0).scale(xMoveFactor);
		Vector3f zMoveComponent = (Vector3f) new Vector3f(0,0,1).scale(zMoveFactor);

		Vector3f localSum = new Vector3f();
		Vector3f.add(xMoveComponent, zMoveComponent, localSum);
		
		Vector3f.add(localSum, sum, sum);
	}
	
	@Override
	public boolean isPlayer() {
		return true;
	}
	
	@Override
	public void decreaseAwaitingTimes(long elapsedTime) {
		timeToWaitBeforeNextAttack = getDecreasedAwaitingTime(elapsedTime, timeToWaitBeforeNextAttack);
	}
	
	public float getHealthExtent() {
		return (float) health / DEF_MAX_HEALTH;
	}

	public void pickItem(Item item) {
        switch (item.getType()) {
	        case ROCKET:
	        	weapon.addAmmo(1);
	            break;
	            
	        case MEDKIT:
	        	if(health == DEF_MAX_HEALTH) {
	        		return;
	        	}
	        	health = ((health + 50) > DEF_MAX_HEALTH) ? DEF_MAX_HEALTH : health + 50;
	            break;
	        	
	        case EXIT:
	        	isWon = true;
	        	break;
	        	
	        case ENERGY:
	        	break;
        }
        item.removeItem();
        //sound
	}
	
	//basic getters and setters below
	
	public int getHealth() {
		return health;
	}
	
	public Model getModel() {
		return model;
	}
	
	public void setCamera(Camera camera) {
		this.camera = camera;
	}

	public boolean isWon() {
		return isWon;
	}
}
